import { VisualizationEvent } from "../components/FeatureProcessor";

export class SpectralCentroidLayer {
  private canvas: HTMLCanvasElement;
  private ctx: CanvasRenderingContext2D;
  private isPlaying: boolean = false;
  private animationFrameId: number | null = null;
  private barCount: number = 128; // Number of bars in the circle
  private barData: number[] = new Array(128).fill(0); // Current bar heights
  private smoothedData: number[] = new Array(128).fill(0); // Smoothed bar heights

  constructor(canvas: HTMLCanvasElement) {
    this.canvas = canvas;
    const ctx = canvas.getContext('2d');
    if (!ctx) {
      throw new Error('Unable to get 2D context');
    }
    this.ctx = ctx;
  }

  public update(event: VisualizationEvent): void {
    if (!this.isPlaying) return;

    // Update bar data based on spectral data
    // We'll use a portion of the MFCCs and other features to drive the visualization
    const centerX = this.canvas.width / 2;
    const centerY = this.canvas.height / 2;
    
    // Convert linear bar data to circular arrangement
    this.draw(centerX, centerY, event);
  }

  private draw(centerX: number, centerY: number, event: VisualizationEvent): void {
    // Do not clear canvas to preserve other layers - only draw the bars
    
    const radius = Math.min(this.canvas.width, this.canvas.height) * 0.1; // 减小半径 (Reduced radius from 0.15 to 0.1)
    const barWidth = (Math.PI * 2) / this.barCount; // Width of each bar in radians
    
    // Update bar data with new values from event
    // ONLY using Spectral Centroid for bar length
    for (let i = 0; i < this.barCount; i++) {
      // Use spectral centroid with position-based variation
      const positionFactor = Math.sin(i * 0.5) * 0.5 + 0.5; // Position-based variation to avoid uniformity
      
      // Normalize and amplify spectral centroid
      const normalizedCentroid = Math.min(5, event.spectralCentroid / 500); // 降低最大值 (Reduced max value from 10 to 5)
      
      const combinedValue = normalizedCentroid * positionFactor;
      
      // Apply smoothing to make animation less jittery but still responsive
      this.barData[i] = this.barData[i] * 0.3 + combinedValue * 0.7; // 调整平滑系数 (Adjusted smoothing coefficients)
    }
    
    // Draw bars in a circle
    this.ctx.save();
    this.ctx.translate(centerX, centerY);
    
    for (let i = 0; i < this.barCount; i++) {
      const angle = i * barWidth - Math.PI / 2; // Start from top (-90 degrees)
      
      // Apply smoothing to the bars
      this.smoothedData[i] = this.smoothedData[i] * 0.2 + this.barData[i] * 0.8; // 调整平滑系数 (Adjusted smoothing coefficients)
      
      // Calculate bar height based ONLY on spectral centroid data
      // Base height of 1 + variable height up to 100 for more visual impact (减小最大高度)
      let barHeight;
      if (this.smoothedData[i] < 0.1) {
        barHeight = 1 + this.smoothedData[i] * 15; // 减小缩放因子 (Reduced scaling factor)
      } else if (this.smoothedData[i] < 1) {
        barHeight = 2 + Math.pow(this.smoothedData[i], 2) * 50; // 减小最大值 (Reduced max values)
      } else {
        barHeight = 3 + Math.pow(this.smoothedData[i], 3) * 80; // 减小最大值 (Reduced max values)
      }
      
      barHeight = Math.min(100, barHeight); // 减小最大高度 (Reduced max height from 200 to 100)
      
      // Create gradient for the bar (rainbow colors)
      const gradient = this.ctx.createLinearGradient(
        0, 0, 
        Math.cos(angle) * barHeight, 
        Math.sin(angle) * barHeight
      );
      
      // Rainbow color based on position
      const hue = (i * 360 / this.barCount) % 360;
      const energyHue = (hue + event.spectralCentroid / 30) % 360;
      
      gradient.addColorStop(0, `hsla(${energyHue}, 90%, 60%, 0.8)`); // 调整饱和度和透明度
      gradient.addColorStop(1, `hsla(${(energyHue + 30) % 360}, 90%, 50%, 0.7)`); // 调整饱和度和透明度
      
      // Draw the bar
      this.ctx.beginPath();
      this.ctx.moveTo(
        Math.cos(angle) * radius,
        Math.sin(angle) * radius
      );
      this.ctx.lineTo(
        Math.cos(angle) * (radius + barHeight),
        Math.sin(angle) * (radius + barHeight)
      );
      
      this.ctx.strokeStyle = gradient;
      // Variable line width based on spectral centroid for more visual impact
      const lineWidth = Math.min(10, Math.max(1, barWidth * radius * (0.2 + this.smoothedData[i] * 0.8))); // 减小线宽
      this.ctx.lineWidth = lineWidth;
      this.ctx.lineCap = 'round';
      this.ctx.shadowBlur = Math.min(15, this.smoothedData[i] * 15); // 减小阴影模糊
      this.ctx.shadowColor = `hsla(${energyHue}, 90%, 50%, 0.6)`; // 调整透明度
      this.ctx.stroke();
      this.ctx.shadowBlur = 0; // Reset shadow
    }
    
    this.ctx.restore();
  }

  public play(): void {
    this.isPlaying = true;
    this.animate();
  }

  public pause(): void {
    this.isPlaying = false;
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
      this.animationFrameId = null;
    }
  }

  private animate(): void {
    if (!this.isPlaying) return;
    
    // We don't draw directly here since we need event data
    // Drawing happens in the update method
    this.animationFrameId = requestAnimationFrame(() => this.animate());
  }

  public resize(width: number, height: number): void {
    this.canvas.width = width;
    this.canvas.height = height;
  }
}